//
//  FuelLogAppDelegate.m
//  FuelLog
//
//  Created by Pure Mass Communications on 9/1/08.
//  Copyright 2008 . All rights reserved.
//
//  Placed under GPL v2 with the kind permission of Pure Mass Communications
//
//  Modified to make compile under SDK 3.1 by Olaf Greck in May 2010
//
//
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License
//  as published by the Free Software Foundation; either version 2
//  of the License, or (at your option) any later version.

//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.

//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#import "FuelLogAppDelegate.h"
#import "FuelLogViewController.h"

static Pref *__pref;

@interface FuelLogAppDelegate (Private)
- (void)createEditableCopyOfDatabaseIfNeeded;
- (void)initializeFromDatabase;
- (Car *)resetCurrentCar:(Car *) car;
- (void)resetSections;
@end

@implementation FuelLogAppDelegate

@synthesize window, viewController, cars, pumps, currentCar, sections;
@synthesize dateSelected;
@synthesize username, password;
@synthesize defaultDateFormatter, googDateFormatter;
@synthesize language;

+ (Pref *)pref {
	return __pref;
}

+ (NSDate *)getNoonUTC:(NSDate	*)date {
	NSCalendar *cal = [NSCalendar currentCalendar];
	unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
	NSDateComponents *comps = [cal components:unitFlags fromDate:date];
	[comps setHour:12];
	[comps setMinute:0];
	[comps setSecond:0];
	NSDate *noon = [cal dateFromComponents:comps];
	int catchup = [[NSTimeZone defaultTimeZone] secondsFromGMTForDate:noon];
	NSDate *gmtNoon = [NSDate dateWithTimeIntervalSince1970:catchup + [noon timeIntervalSince1970]];
	return gmtNoon;
}

+ (NSDate *)getMonthsBefore:(NSDate *)date months:(int) months {
	NSCalendar *cal = [NSCalendar currentCalendar];
	NSDateComponents *comps = [[NSDateComponents alloc] init];
	[comps setMonth:(0-months)];
	NSDate *before = [cal dateByAddingComponents:comps toDate:date options:0];
	[comps release];
	return before;
}

+ (float) scanFloat:(NSString *)aString {
	float value = 0.0;
	[[NSScanner localizedScannerWithString:aString] scanFloat:&value];
	return value;
}

#pragma mark -
- (NSString *)countryPrefix {
	return [[countryPrefix retain] autorelease];
}



- (void)setCountryPrefix:(NSString *)value {
    if (self.language != value) {
        [self.language release];
        self.language = [value copy];	
	}
	value = [value stringByAppendingString:@".lproj/"];
    if (countryPrefix != value) {
        [countryPrefix release];
        countryPrefix = [value copy];
    }
}
//#error 
#warning check italian localisation below
-(void) checkConfiguredlanguage {
	[self setCountryPrefix:@"English"]; 
	[self setLanguage:@"English"]; 
	NSArray * preferedLanguages= [NSLocale preferredLanguages];
	//	for (NSString * languageString in preferedLanguages) {
	NSString * languageString = [preferedLanguages objectAtIndex:0];
	if ([[languageString substringToIndex:2] isEqualToString:@"de"]) {
		[self setCountryPrefix:@"de"];				
		[self setLanguage:@"de"];
		//break;
	}
	if ([[languageString substringToIndex:2] isEqualToString:@"it"]) {
		[self setCountryPrefix:@"it"];				
		[self setLanguage:@"it"];
	}
	if ([[languageString substringToIndex:2] isEqualToString:@"pt"]) {
		[self setCountryPrefix:@"pt"];				
		[self setLanguage:@"pt"];
		//	break;
	}
	if ([[languageString substringToIndex:2] isEqualToString:@"es"]) {
		[self setCountryPrefix:@"es"];				
		[self setLanguage:@"es"];
		//	break;
	}
	//} // commented , matched for loop above
}
#pragma mark -

#pragma mark -

- (void)applicationDidFinishLaunching:(UIApplication *)application {	
	if(
	   getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled")
	   ) {
		NSLog(@"NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled enabled!");
	}
	firstTimeAppRunsMyCar = TRUE;
	firstTimeAppRunsPrefs = TRUE;
	databaseIsOpen = FALSE;
	
	[self checkConfiguredlanguage];
    [self createEditableCopyOfDatabaseIfNeeded];
	[self initializeFromDatabase];
	if (firstTimeAppRunsMyCar)  
	{ 
		currentCar.label = (NSLocalizedString(@"AppDelegate localName for My Car",@"My Car"));
		firstTimeAppRunsMyCar = FALSE;
	}
    username = @"";
	password = @"";
	defaultDateFormatter = [[NSDateFormatter alloc] init];
	[defaultDateFormatter setDateFormat:@"yyyy/MM/dd"];
	googDateFormatter = [[NSDateFormatter alloc] init];
	[googDateFormatter setDateFormat:@"M/d/yyyy"];
	
	dateSelected = [[NSMutableDictionary alloc] init];
	navigationController = [[UINavigationController alloc] init];
	navigationController.toolbarHidden = NO;
	
 	self.viewController = [[FuelLogViewController alloc] 
								  initWithNibName:@"FuelLogViewController" bundle:nil];
	[navigationController pushViewController:viewController animated:NO];
	navigationController.navigationBar.barStyle = UIStatusBarStyleBlackTranslucent;
	navigationController.toolbar.barStyle = UIStatusBarStyleBlackTranslucent;
	// Override point for customization after app launch	
   // [window addSubview:viewController.view];
	[self.window addSubview:navigationController.view];
	[window makeKeyAndVisible];
//	[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
	[self openDB];
}

- (void)applicationWillResignActive:(UIApplication *)application {
	[self closeDB];
	[self exportToCsvFile];
}

- (void)openDB {
	if (!databaseIsOpen) {
		NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
		
		NSString *libraryDirectory = [paths objectAtIndex:0];
		NSString *path = [libraryDirectory stringByAppendingPathComponent:@"gasoline.sqlite"];
		// Open the database. The database was prepared outside the application.
		if (sqlite3_open([path UTF8String], &database) != SQLITE_OK) {
			sqlite3_close(database);
			NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
		}
		databaseIsOpen = TRUE;
		
	}
}
- (void) closeDB {
	if (databaseIsOpen) {
		[cars makeObjectsPerformSelector:@selector(updateDatabase)];
		[Car finalizeStatements];
		[pumps makeObjectsPerformSelector:@selector(updateDatabase)];
		[Gas finalizeStatements];
		[Pref finalizeStatements]; 
		if (sqlite3_close(database) != SQLITE_OK) {
			NSAssert1(0, @"Error: failed to close database with message '%s'.", sqlite3_errmsg(database));
		}
		databaseIsOpen = FALSE;
	}
}

- (void)applicationWillTerminate:(UIApplication *)application {
	NSString *reqSysVer = @"4.0";
	NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
	if (![currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) [self closeDB];
	reqSysVer = @"3.2";
	if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) [self exportToCsvFile];
}


- (void)dealloc {
	[FuelLogViewController staticCleanUp];
    [viewController release];
	[window release];
	[cars release];
	[pumps release];
	[sections release];
	[defaultDateFormatter release];
	[googDateFormatter release];
	[super dealloc];
}
#pragma mark -


-(void)exportToCsvFile {
    const char * localizedHeader = [Gas exportCsvHeaderLocalized];
	NSMutableData *csvData = [NSMutableData dataWithBytes:localizedHeader length:strlen(localizedHeader)];
	const char * rowData;
	for (int i = [pumps count] - 1; i >= 0; --i) {
		Gas *gas = (Gas *)[pumps objectAtIndex:i];
		rowData = [gas exportCsvRowLocalized:defaultDateFormatter];
		[csvData appendBytes:rowData length:strlen(rowData)];
	}
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];      
	//************
	// The good stuff is from http://simonwoodside.com/weblog/2009/4/22/how_to_really_url_encode/ !
	NSString * fileName = (NSString *)CFURLCreateStringByAddingPercentEscapes(
																			  NULL,
																			  (CFStringRef)currentCar.label,
																			  NULL,
																			  (CFStringRef)@"!*'();:@&=+$,/?%#[]",
																			  kCFStringEncodingUTF8 );
	
	//**********
	NSString *fileNameWithExtension = [fileName stringByAppendingString:@".csv"];
	
    NSString *fileNameWithPath = [documentsDirectory stringByAppendingPathComponent:fileNameWithExtension];
	[csvData writeToFile:fileNameWithPath atomically:YES];
}

#pragma mark -
// Creates a writable copy of the bundled default database in the application Documents directory.
- (void)createEditableCopyOfDatabaseIfNeeded {
    // First, test for existence.
    BOOL success;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
	paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
    NSString *libraryDirectory = [paths objectAtIndex:0];
    NSString *pre3dot5DBPath = [documentsDirectory stringByAppendingPathComponent:@"gasoline.sqlite"];
	NSString * libDirDBPath = [libraryDirectory stringByAppendingPathComponent:@"gasoline.sqlite"];
	
	//   success = [fileManager fileExistsAtPath:pre3dot5DBPath]; // DB still in ~/Documents
    if (![fileManager fileExistsAtPath:pre3dot5DBPath] && // not DB  in ~/Documents (pre v3.5 location)
		![fileManager fileExistsAtPath:libDirDBPath]) { // not DB in ~/Library (new location v3.5+)
		firstTimeAppRunsMyCar = TRUE ; 
		firstTimeAppRunsPrefs = TRUE;
		// The writable database does not exist, so copy the default to the appropriate location.
		NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"gasoline.sqlite"];
		
		success = [fileManager copyItemAtPath:defaultDBPath toPath:libDirDBPath error:&error];
		if (!success) {
			NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
		}
	}
	if ([fileManager fileExistsAtPath:pre3dot5DBPath] && // yes DB  in ~/Documents (pre v3.5 location)
		![fileManager fileExistsAtPath:libDirDBPath]) { // not DB in ~/Library (new location v3.5+)
		firstTimeAppRunsMyCar = FALSE ; 
		firstTimeAppRunsPrefs = FALSE;
		// move db form  ~/Documents to ~/Library
		success = [fileManager moveItemAtPath:pre3dot5DBPath toPath:libDirDBPath error:&error];
		if (!success) {
			NSAssert1(0, @"Failed to copy DB from old to new location with message '%@'.", [error localizedDescription]);
		}
	}
	if (![fileManager fileExistsAtPath:pre3dot5DBPath] && // no DB  in ~/Documents (pre v3.5 location)
		[fileManager fileExistsAtPath:libDirDBPath]) { // yes DB in ~/Library (new location v3.5+)
		firstTimeAppRunsMyCar = FALSE ; 
		firstTimeAppRunsPrefs = FALSE;
	}
	
}

// Open the database connection and retrieve current objects
- (void)initializeFromDatabase {
	[self openDB];
	__pref = [Pref getAll:database];
	if (firstTimeAppRunsPrefs)
	{
		if ([self.countryPrefix isEqualToString:@"de.lproj/"]) { // l/100km fuer deutsch sprechende
			__pref.units = INV_METRIC;
			__pref.costDigits = 2;
		}
		if ([self.countryPrefix isEqualToString:@"it.lproj/"]) { // km per litro per italiani
			__pref.units = METRIC;
			__pref.costDigits = 2;
		}
			 firstTimeAppRunsPrefs = FALSE;
	}
	cars = [[NSMutableArray alloc] init];
	[Car getAll:cars database:database];
	currentCar = nil;
	for (int i = 0; i<[cars count]; ++i) {
		currentCar = (Car *) [cars objectAtIndex:i];
		if (currentCar.selected)  break;
	}
	pumps = [[NSMutableArray alloc] init];
	sections = nil;
	if (currentCar) {
		[Gas getAll:pumps car_id:currentCar.pk database:database];
		[self resetSections];
		if (!currentCar.selected) {
			[currentCar setSelected:YES];
		}
	}
}

- (Car *) resetCurrentCar:(Car *) car {
	if (currentCar == car) {
		return currentCar;
	}
	if (currentCar) {
		[currentCar setSelected:NO];
	}
	[car setSelected:YES];
	[pumps makeObjectsPerformSelector:@selector(updateDatabase)];
	[pumps removeAllObjects];
	currentCar = car;
	[Gas getAll:pumps car_id:currentCar.pk database:database];
	[self resetSections];
	return currentCar;
}



#pragma mark -

- (void)addCar:(Car *)car {
	if (car) {
		[car insertIntoDatabase:database];
		[cars addObject:car];
	}
}

- (BOOL)hasCar:(NSString *)name {
	if (name) {
		for (int i = 0; i < [cars count]; ++i) {
			if ([name isEqualToString:((Car *)[cars objectAtIndex:i]).label]) {
				return YES;
			}
		}
	}
	return NO;
}

- (Car *)chooseCar:(Car *) car {
	if (currentCar == car) {
		return currentCar;
	}
	return [self resetCurrentCar:car];
}

- (Car *)chooseCarByKey:(int) pk {
	if (currentCar) {
		if (currentCar.pk == pk) {
			return currentCar;
		}
	}
	for (int i = 0; i < [cars count]; ++i) {
		Car *car = (Car *)[cars objectAtIndex:i];
		if (car.pk == pk) {
			return [self chooseCar:car];
		}
	}
	return currentCar;
}

- (Car *)chooseCarByIndex:(int) idx {
	Car *car = (Car *)[cars objectAtIndex:idx];
	return [self chooseCar:car];
}

- (void)removeCar:(Car *) car {
	if (car && car.pk != -1) {
		BOOL selected = car.selected;
		[Gas deleteForCar:car.database car_id:car.pk];
		if ([cars count] == 1) {
			car.label = (NSLocalizedString(@"AppDelegate_removeCar My Car",@"My Car"));
			[car updateDatabase];
		} else {
			if (car == currentCar) {
				int idx = [cars indexOfObjectIdenticalTo:car];
				if (idx < [cars count] - 1) {
					Car *kar = (Car *)[cars objectAtIndex:idx + 1];
					[self resetCurrentCar:kar];
				} else {
					for (int i = 0; i < [cars count]; ++i) {
						Car *kar = (Car *)[cars objectAtIndex:i];
						if (kar.pk != car.pk) {
							[self resetCurrentCar:kar];
							break;
						}
					}
				}
			}
			[car deleteFromDatabase];
			[cars removeObject:car];
		}
		if (selected && cars.count > 0) 
			[self chooseCarByIndex:0];
	}
}

- (void)addGas:(Gas *)gas {
	if (gas) {
		[gas insertIntoDatabase:database];
		[pumps addObject:gas];
		[self resetSections];
	}
}

- (void)addGasIfNeeded:(Gas *)gas previous:(Gas *)prev next:(Gas *)next {
	int begin = pumps.count;
	if (prev) begin = [pumps indexOfObjectIdenticalTo:prev];
	int end = 0;
	if (next) end = [pumps indexOfObjectIdenticalTo:next];
	if (gas.pk >= 0) {
		int now = [pumps indexOfObjectIdenticalTo:gas];
		if (now > begin || now < end) {
			[pumps removeObjectAtIndex:now];
			if (now < end) {
				begin--;
				end--;
			}
		} else {
			return;
		}
	} else {
		[gas insertIntoDatabase:database];
	}
	[pumps insertObject:gas atIndex:begin];
	[self resetSections];
}

- (void)removeGas:(Gas *) gas {
	if (gas) {
		[gas deleteFromDatabase];
		[pumps removeObject:gas];
		[self resetSections];
	}
}

- (Gas *)findPreviousGasEntry:(NSDate *)date odometer:(float)odometer {
	for (int i = 0; i < pumps.count; ++i) {
		Gas *gas = (Gas *)[pumps objectAtIndex:i];
		if (gas.odometer < odometer || [gas.date compare:date] == NSOrderedAscending) 
			return gas;
	}	
	return nil;
}

- (Gas *)findNextGasEntry:(NSDate *)date odometer:(float)odometer {
	for (int i = pumps.count - 1; i >= 0; --i) {
		Gas *gas = (Gas *)[pumps objectAtIndex:i];
		if (gas.odometer > odometer || [gas.date compare:date] == NSOrderedDescending) 
			return gas;
	}
	return nil;
}

- (float)gasEconomy:(int)pk odometer:(float)odometer fuel:(float)volume {
	if (volume <= 0.0) return 0.0;
	for (int i = 0; i < pumps.count; ++i) {
		Gas *gas = (Gas *)[pumps objectAtIndex:i];
		if (gas.pk == pk || gas.odometer > odometer) 
			continue;
		if (gas.full) 
			return (odometer - gas.odometer) / volume;
		else
			volume += gas.volume;
	}	
	return 0.0;	
}

- (void)resetSections {
	if (sections != nil) {
		[sections removeAllObjects];
	} else {
		sections = [[NSMutableArray alloc] initWithCapacity:5];
	}
	NSCalendar *cal = [NSCalendar currentCalendar];
	int year = -1;
	for (int i = 0; i < pumps.count; ++i) {
		Gas *gas = (Gas *)[pumps objectAtIndex:i];
		int y = [[cal components:NSYearCalendarUnit fromDate:gas.date] year];
		if (y != year) {
			[sections addObject:[NSNumber numberWithInt:i]];
			year = y;
		}
	}	
}

@end
